package com.clp.protocol.iec104.iec104;

import com.clp.protocol.iec104.iec104.client.Iec104Client;
import com.clp.protocol.iec104.iec104.client.async.MasterFuture;
import com.clp.protocol.iec104.iec104.client.config.MasterConfig;
import com.clp.protocol.iec104.iec104.server.Iec104Server;
import com.clp.protocol.iec104.iec104.server.slave.SlaveConfig;
import com.clp.protocol.iec104.iec104.server.slave.SlaveControlConfig;
import com.clp.protocol.iec104.iec104.server.slave.SlaveDataConfig;
import com.clp.protocol.iec104.iec104.server.slave.async.SlaveFuture;
import com.clp.protocol.iec104.iec104.server.slave.async.SlaveFutureListener;
import com.clp.protocol.iec104.iec104.server.slavechannel.SlaveChannel;
import com.clp.protocol.iec104.iec104.server.slavechannel.pipeline.filter.IpWhiteListFilterRule;
import com.clp.protocol.iec104.iec104.server.slavechannel.pipeline.state.data.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class TestClient {
    public static void main(String[] args) throws InterruptedException {
        String ip = "127.0.0.1";
        Iec104Client client = Iec104Client.get();
        MasterFuture<Void> connectFuture = client.connect(MasterConfig.configurer().connection(ip, 2404).configOk());


        Thread.sleep(60* 60 * 1000);
    }
}


public class TestServer {
    public static void main(String[] args) throws Throwable {
        Iec104Server server = Iec104Server.get();

        ExecutorService executorService = Executors.newFixedThreadPool(4);

        SlaveFuture<Void> slaveFuture = server.open(
                SlaveConfig.configurer()
                        .controlConfig(SlaveControlConfig.configurer()
                                        .ipFilterRule(new IpWhiteListFilterRule("127.0.0.1", "123.132.213.231"))
                                        .configOk()
                        )
                        .dataConfig(SlaveDataConfig.configurer()
                                .totalCall100DataReactor(new TotalCall100DataReactor(executorService, TotalCall100DataReactor.TmDataType.FLOAT,
                                        TotalCall100DataReactor.TsDataType.ONE_POINT) {
                                    @Override
                                    protected boolean accept0(SlaveChannel slaveChannel) {
                                        return true;
                                    }

                                    @Override
                                    protected List<TmData> collectTmData0(SlaveChannel slaveChannel) {
                                        List<TmData> tmDataList = new ArrayList<>(100);
                                        Random random = new Random();
                                        for (int i = 0; i < 100; i++) {
                                            if (random.nextBoolean()) {
                                                int addr = i;
                                                tmDataList.add(new TmData() {
                                                    @Override
                                                    public BigDecimal getValue() {
                                                        return BigDecimal.valueOf(0);
                                                    }

                                                    @Override
                                                    public boolean isValid() {
                                                        return true;
                                                    }

                                                    @Override
                                                    public int getAddress() {
                                                        return addr;
                                                    }
                                                });
                                            }
                                        }
                                        return tmDataList;
                                    }

                                    @Override
                                    protected List<TsData> collectTsData0(SlaveChannel slaveChannel) {
                                        List<TsData> tsDataList = new ArrayList<>(100);
                                        Random random = new Random();
                                        for (int i = 0; i < 100; i++) {
                                            if (random.nextBoolean()) {
                                                int addr = i;
                                                tsDataList.add(new TsData() {
                                                    @Override
                                                    public boolean isSwitchOn() {
                                                        return random.nextBoolean();
                                                    }

                                                    @Override
                                                    public boolean isValid() {
                                                        return true;
                                                    }

                                                    @Override
                                                    public boolean isCurrVal() {
                                                        return true;
                                                    }

                                                    @Override
                                                    public boolean isReplaced() {
                                                        return false;
                                                    }

                                                    @Override
                                                    public boolean isLocked() {
                                                        return false;
                                                    }

                                                    @Override
                                                    public int getAddress() {
                                                        return addr;
                                                    }
                                                });
                                            }
                                        }
                                        return tsDataList;
                                    }
                                })
                                .totalCall101DataReactor(new TotalCall101DataReactor(executorService,
                                        TotalCall101DataReactor.TpDataType.CUMULANT) {
                                    @Override
                                    protected boolean accept0(SlaveChannel slaveChannel) {
                                        return true;
                                    }

                                    @Override
                                    protected List<TpData> collectTpData0(SlaveChannel slaveChannel) {
                                        List<TpData> tpDataList = new ArrayList<>(100);
                                        Random random = new Random();
                                        for (int i = 0; i < 100; i++) {
                                            if (random.nextBoolean()) {
                                                int addr = i;
                                                tpDataList.add(new TpData() {
                                                    @Override
                                                    public long getValue() {
                                                        return 0;
                                                    }

                                                    @Override
                                                    public boolean isValid() {
                                                        return true;
                                                    }

                                                    @Override
                                                    public boolean isAdjusted() {
                                                        return false;
                                                    }

                                                    @Override
                                                    public boolean isOverflowed() {
                                                        return false;
                                                    }

                                                    @Override
                                                    public int getSeq() {
                                                        return 0;
                                                    }

                                                    @Override
                                                    public int getAddress() {
                                                        return addr;
                                                    }
                                                });
                                            }
                                        }
                                        return tpDataList;
                                    }
                                })
                                .tcDataReactor(new TcDataReactor(executorService, TcDataReactor.TcType.ONE_POINT) {
                                    @Override
                                    public CompletableFuture<Boolean> acceptSelect(SlaveChannel slaveChannel) {
                                        return supplyAsync(() -> true);
                                    }

                                    @Override
                                    public CompletableFuture<Boolean> acceptExecute(SlaveChannel slaveChannel) {
                                        return supplyAsync(() -> true);
                                    }
                                })
                                .configOk()
                        )
                        .local("172.18.83.112", 2404)
                        .configOk()
        );
        slaveFuture.addListener(new SlaveFutureListener<Void>() {
            @Override
            public void operationComplete(SlaveFuture<Void> future) {
                if (future.isSuccess()) {
                    System.out.println("端口打开成功");
                } else {
                    System.out.println("端口打开失败,原因：" + future.cause());
                }
            }
        });


        Thread.sleep(60 * 60 * 1000);
//        Thread.sleep( 10 * 1000);

        server.close(slaveFuture.slave());
        executorService.shutdown();
    }
}
